<% if false # the license inside this if block assertains to this file -%>
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
<% end -%>
def create_change(original, updated, resource)
  create_req = ::Google::<%= product_ns -%>::Network::Post.new(
    collection(resource), fetch_auth(resource),
    'application/json', resource_to_change_request(original, updated)
  )
  return_if_change_object create_req.send
end

# Fetch current SOA. We need the last SOA so we can increment its serial
def update_soa
  original_soa = prefetch_soa_resource

  # Create a clone of the SOA record so we can update it
  updated_soa = original_soa.clone
  updated_soa.each_key do |k|
    updated_soa[k] = original_soa[k].clone \
      unless original_soa[k].is_a?(Integer)
  end

  soa_parts = updated_soa['rrdatas'][0].split(' ')
  soa_parts[2] = soa_parts[2].to_i + 1
  updated_soa['rrdatas'][0] = soa_parts.join(' ')
  [original_soa, updated_soa]
end

def resource_to_change_request(original_record, updated_record)
  original_soa, updated_soa = update_soa
  result = new_change_request
  add_additions result, updated_soa, updated_record
  add_deletions result, original_soa, original_record
  ::Google::HashUtils.camelize_keys(result).to_json
end

def add_additions(result, updated_soa, updated_record)
  result[:additions] << updated_soa unless updated_soa.nil?
  result[:additions] << updated_record unless updated_record.nil?
end

def add_deletions(result, original_soa, original_record)
  result[:deletions] << original_soa unless original_soa.nil?
  result[:deletions] << original_record unless original_record.nil?
end

# TODO(nelsonjr): Merge and delete this code once async operations
# declared in api.yaml is moved to master from:
#   https://cloud-internal.googlesource.com/cloud-graphite-team/
#   config-modules/codegen/+/
#   2ccb0eb5cb207f67b297c6058d2455240d7316bf/
#   compute/api.yaml#9
def wait_for_change_to_complete(change_id, resource)
  status = 'pending'
  while status == 'pending'
    debug("waiting for transaction '#{change_id}' to complete")
    status = get_change_status(change_id, resource)
    sleep(0.5) unless status == 'done'
  end
  debug("transaction '#{change_id}' complete")
end

def get_change_status(change_id, resource)
  change_req = ::Google::<%= product_ns -%>::Network::Get.new(
    collection(resource, '/{{id}}', id: change_id), fetch_auth(resource)
  )
  return_if_change_object(change_req.send)['status']
end

def new_change_request
  {
    kind: 'dns#change',
    additions: [],
    deletions: [],
    start_time: Time.now.iso8601
  }
end

def return_if_change_object(response)
  raise "Bad request: #{response.body}" \
    if response.is_a?(Net::HTTPBadRequest)
  raise "Bad response: #{response}" \
    unless response.is_a?(Net::HTTPResponse)
  return unless response.class >= Net::HTTPOK
  result = JSON.parse(response.body)
  raise "Incorrect result: #{result['kind']}" \
    unless result['kind'] == 'dns#change'
  result
end

def fetch_resource(resource, self_link, kind)
  self.class.fetch_resource(resource, self_link, kind)
end
